<!-- 
  菜单选择组件
  1. 获取所有的菜单数据渲染
    /admin/base/sys/menu/list
  2. 获取勾选的数据
    getCheckedKeys() - 默认返回的是勾选上的数据
    getHalfCheckedKeys() - 默认返回半勾选上的数据
  3. 支持v-model
    数据回填会有个问题，父级id传递的话，会导致所有的子级都给勾选
    [46, 15, 14, 1, 2]  => [46, 15]
    只保留叶子节点Id
 -->

<template>
  <el-space class="menu-check" direction="vertical">
    <div class="menu-check__header">
      <el-input v-model="filterText" placeholder="输入关键字进行过滤" />
    </div>

    <div class="menu-check__body">
      <el-scrollbar height="200">
        <el-tree
          ref="treeRef"
          node-key="id"
          :data="treeData"
          :props="{ label: 'name' }"
          :filter-node-method="filterNode"
          show-checkbox
          @check="handleCheck"
        />
      </el-scrollbar>
    </div>
  </el-space>
</template>

<script>
import { getSysMenuList } from "@/api/sys";
import { listToTree } from "@/utils/common";

export default {
  name: "MenuCheck",

  props: ["modelValue"],

  emits: ["update:modelValue"],

  data() {
    return {
      filterText: "",
      menus: [],
    };
  },

  watch: {
    modelValue: {
      handler(newVal) {
        // 针对 modelValue 做过滤，只保留叶子节点Id
        // [46, 15, 14, 1, 2]  => [46, 15]
        const keys = newVal.filter((item) => {
          // 判断 item 这个Id 是否为叶子节点Id。menus 的所有节点没有 parentId 为 item 的
          return this.menus.every((menu) => menu.parentId !== item);
        });

        // 手动调用 setCheckedKeys()
        this.$nextTick(() => {
          this.$refs.treeRef?.setCheckedKeys(keys);
        });
      },
      deep: true,
      immediate: true,
    },

    filterText(newVal) {
      this.$refs.treeRef.filter(newVal);
    },
  },

  computed: {
    treeData() {
      return listToTree(this.menus);
    },
  },

  methods: {
    async refresh() {
      const result = await getSysMenuList();
      this.menus = result;
    },

    handleCheck() {
      // 1. 获取勾选与半勾选的Ids
      const keys = [
        ...this.$refs.treeRef.getCheckedKeys(),
        ...this.$refs.treeRef.getHalfCheckedKeys(),
      ];

      // 2. 触发 update:modelValue 自定义事件
      this.$emit("update:modelValue", keys);
    },

    /**
     * 过滤节点的函数
     * @param {*} value 调用 filter 方法时，传递的参数
     * @param {*} node  一个树节点
     * @returns {boolean} true，当前节点就会被显示
     */
    filterNode(value, node) {
      return node.name.includes(value);
    },

    fn1() {
      this.$refs.treeRef.filter("张三");
    },
  },

  created() {
    this.refresh();
  },
};
</script>

<style scoped>
.menu-check {
  width: 100%;
}
.menu-check__body {
  padding: 5px 0;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
}
</style>
